package run.halo.app.service.front.impl;

import cn.hutool.core.util.ObjectUtil;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.sms.v20210111.SmsClient;
import com.tencentcloudapi.sms.v20210111.models.SendSmsRequest;
import com.tencentcloudapi.sms.v20210111.models.SendSmsResponse;
import com.tencentcloudapi.sms.v20210111.models.SendStatus;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import run.halo.app.model.support.FrontConstant;
import run.halo.app.service.front.MsgService;
import java.util.concurrent.TimeUnit;

@Service
public class MsgServiceImpl implements MsgService {

    private static final int EXPR_TIME = 5;
    private static final String OK_RESULT = "Ok";
    @Autowired
    private final StringRedisTemplate redisTemplate;

    @Value("${msg.tencent.secretId}")
    private String secretId;
    @Value("${msg.tencent.secretKey}")
    private String secretKey;
    @Value("${msg.tencent.sdkAppId}")
    private String sdkAppId;
    @Value("${msg.tencent.signName}")
    private String signName;
    @Value("${msg.tencent.templateId}")
    private String templateId;
    //过期时间 5分钟

    public MsgServiceImpl(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    public String sendMobileMsg(String phoneNumber,String ip) {
        if(checkSendMobile(phoneNumber)){
            return "请1分钟后再发送！";
        }
        try {
            Credential cred = new Credential(secretId, secretKey);
            // 实例化一个http选项，可选，没有特殊需求可以跳过
            HttpProfile httpProfile = new HttpProfile();
            // 设置代理（无需要直接忽略）
            // httpProfile.setProxyHost("真实代理ip");
            // httpProfile.setProxyPort(真实代理端口);
            /* SDK默认使用POST方法。
             * 如果你一定要使用GET方法，可以在这里设置。GET方法无法处理一些较大的请求 */
            httpProfile.setReqMethod("POST");
            /* SDK有默认的超时时间，非必要请不要进行调整
             * 如有需要请在代码中查阅以获取最新的默认值 */
            httpProfile.setConnTimeout(60);
        /* 指定接入地域域名，默认就近地域接入域名为 sms.tencentcloudapi.com ，也支持指定地域域名访问，例如广州地域的域名为 sms.ap-guangzhou
        .tencentcloudapi.com */
            httpProfile.setEndpoint("sms.tencentcloudapi.com");
            /* 非必要步骤:
             * 实例化一个客户端配置对象，可以指定超时时间等配置 */
            ClientProfile clientProfile = new ClientProfile();
            /* SDK默认用TC3-HMAC-SHA256进行签名
             * 非必要请不要修改这个字段 */
            clientProfile.setSignMethod("HmacSHA256");
            clientProfile.setHttpProfile(httpProfile);
            /* 实例化要请求产品(以sms为例)的client对象
             * 第二个参数是地域信息，可以直接填写字符串ap-guangzhou，支持的地域列表参考 https://cloud.tencent
             * .com/document/api/382/52071#.E5.9C.B0.E5.9F.9F.E5.88.97.E8.A1.A8 */
            SmsClient client = new SmsClient(cred, "ap-guangzhou", clientProfile);
            /* 实例化一个请求对象，根据调用的接口和实际情况，可以进一步设置请求参数
             * 你可以直接查询SDK源码确定接口有哪些属性可以设置
             * 属性可能是基本类型，也可能引用了另一个数据结构
             * 推荐使用IDE进行开发，可以方便的跳转查阅各个接口和数据结构的文档说明 */
            SendSmsRequest req = new SendSmsRequest();
            /* 填充请求参数,这里request对象的成员变量即对应接口的入参
             * 你可以通过官网接口文档或跳转到request对象的定义处查看请求参数的定义
             * 基本类型的设置:
             * 帮助链接：
             * 短信控制台: https://console.cloud.tencent.com/smsv2
             * 腾讯云短信小助手: https://cloud.tencent.com/document/product/382/3773#.E6.8A.80.E6.9C.AF
             * .E4.BA
             * .A4.E6.B5.81 */

            /* 短信应用ID: 短信SdkAppId在 [短信控制台] 添加应用后生成的实际SdkAppId，示例如1400006666 */
            // 应用 ID 可前往 [短信控制台](https://console.cloud.tencent.com/smsv2/app-manage) 查看
            req.setSmsSdkAppId(sdkAppId);
            /* 短信签名内容: 使用 UTF-8 编码，必须填写已审核通过的签名 */
            // 签名信息可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-sign) 或 [国际/港澳台短信]
            // (https://console.cloud.tencent.com/smsv2/isms-sign) 的签名管理查看
            req.setSignName(signName);
            /* 模板 ID: 必须填写已审核通过的模板 ID */
            // 模板 ID 可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-template) 或 [国际/港澳台短信]
            // (https://console.cloud.tencent.com/smsv2/isms-template) 的正文模板管理查看
            req.setTemplateId(templateId);
            /* 模板参数: 内容：验证码：{1}，{2}分钟内有效，请勿泄露与他人。下面参数对应模板内容 */
            //随机验证码
            String code = RandomStringUtils.random(6, false, true);
            //短信内容参数
            String[] templateParamSet = {code, EXPR_TIME + ""};
            req.setTemplateParamSet(templateParamSet);
            /* 下发手机号码，采用 E.164 标准，+[国家或地区码][手机号]
             * 示例如：+8613711112222， 其中前面有一个+号 ，86为国家码，13711112222为手机号，最多不要超过200个手机号 */
            //目前只实现了单个发送，后续有需要再实现多好吗发送功能
            String[] phoneNumberSet = {phoneNumber};
            req.setPhoneNumberSet(phoneNumberSet);

            /* 用户的 session 内容（无需要可忽略）: 可以携带用户侧 ID 等上下文信息，server 会原样返回 */
            String sessionContext = "";
            req.setSessionContext(sessionContext);
            /* 国际/港澳台短信 SenderId（无需要可忽略）: 国内短信填空，默认未开通，如需开通请联系 [腾讯云短信小助手] */
            String senderid = "";
            req.setSenderId(senderid);

            /* 通过 client 对象调用 SendSms 方法发起请求。注意请求方法名与请求对象是对应的
             * 返回的 res 是一个 SendSmsResponse 类的实例，与请求对象对应 */
            SendSmsResponse res = client.SendSms(req);
            //发送返回结果
            SendStatus[] sendStatusSet = res.getSendStatusSet();
            SendStatus sendStatus = sendStatusSet[0];
            //发送成功，将短信验证码信息保存到redis中
            if (sendStatus.getCode().equals(OK_RESULT)) {
                redisTemplate.opsForValue()
                    .set(FrontConstant.REDIS_MSG_CODE_KEY + phoneNumber, code, EXPR_TIME,
                        TimeUnit.MINUTES);
                redisTemplate.opsForValue()
                    .set(FrontConstant.REDIS_MSG_CHECK_KEY + phoneNumber, code, 1,
                        TimeUnit.MINUTES);
                //新的IP地址访问时，首次进来，判断30分钟内有没有发送过短信，没有的话设置一个key
                Boolean aBoolean = redisTemplate.hasKey(FrontConstant.REDIS_CLIENT_IP_KEY + ip);
                if(Boolean.FALSE.equals(aBoolean)){
                    redisTemplate.opsForValue().increment(FrontConstant.REDIS_CLIENT_IP_KEY+ip,1);
                    redisTemplate.expire(FrontConstant.REDIS_CLIENT_IP_KEY+ip,30,TimeUnit.MINUTES);
                }else {
                    redisTemplate.opsForValue().increment(FrontConstant.REDIS_CLIENT_IP_KEY+ip,1);
                }
                return "发送短信成功";
            }
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
        }
        return "发送短信失败，请稍后再试";
    }

    boolean checkSendMobile(String phoneNumber){
        String s = redisTemplate.opsForValue().get(FrontConstant.REDIS_MSG_CHECK_KEY + phoneNumber);
        if(ObjectUtil.isNotEmpty(s)){
            return true;
        }
        return false;
    }
}
